/*
 * Copyright (C) 2022 KylinSoft Co., Ltd.
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <https://www.gnu.org/licenses/>.
 */

#include "desktopitemloader.h"
#include <QSettings>
#include <KDesktopFile>
#include <KConfigGroup>
#include "desktopitemhelper.h"
#include "desktopfilemanager.h"
#include "taskbarappmanager.h"
#include "itempositioncalculator.h"

DesktopItemLoader::DesktopItemLoader(DesktopFileManager *desktopFileManager,
                                     DesktopLayout layout,
                                     QObject *parent)
    : QObject{parent}
    , m_desktopFileManager(desktopFileManager)
    , m_desktopLayout(layout)
{

}

void DesktopItemLoader::load()
{
    dissectDesktopFilesToItems();
    loadLocalItems();
    placeItems();
}

void DesktopItemLoader::placeItem(const ItemPositionInfo &itemPosition)
{
    int startRow = itemPosition.startRow;
    int rowSpan = itemPosition.rowSpan;
    int startColumn = itemPosition.startColumn;
    int columnSpan = itemPosition.columnSpan;

    int endRow = startRow + rowSpan;
    int endColumn = startColumn + columnSpan;
    for (; startRow < endRow; ++startRow) {
        startColumn = itemPosition.startColumn;
        for (; startColumn < endColumn; ++startColumn) {
            m_itemIdsInPageGrid[itemPosition.page][startRow][startColumn]
                    = itemPosition.itemId;
        }
    }
}

void DesktopItemLoader::dissectDesktopFilesToItems()
{
    auto localDesktopFiles = m_desktopFileManager->localDesktopFiles();
    for (auto &desktopFileName : qAsConst(localDesktopFiles)) {
        auto *item = DesktopItemHelper::dissectInstalledDesktopFileToItem(desktopFileName,
                                                             m_softwareStoreAppCategory,
                                                             m_allItems.keys());
        m_allItems[item->getId()] = item;
    }
}

TabletDesktopItemLoader::TabletDesktopItemLoader(DesktopFileManager *desktopFileManager,
                                                 TaskbarAppManager *taskbarManger,
                                                 DesktopLayout desktopLayout,
                                                 AppWidget::KAppWidgetManager *appWidgetManager,
                                                 QObject *parent)
    : DesktopItemLoader(desktopFileManager, desktopLayout, parent)
    , m_taskbarAppManager(taskbarManger)
    , m_appWidgetManager(appWidgetManager)
{

}

void TabletDesktopItemLoader::loadLocalItems()
{
    loadTaskbarApps();
    loadDefaultGroup();
    loadAppWidget();    
}

void TabletDesktopItemLoader::placeItems()
{
    // place the app widgets
    if (!m_appWidgetIds.isEmpty()) {
        for (auto &widgetId : qAsConst(m_appWidgetIds)) {
            placeAppWidget(widgetId);
        }
    }
    // place the default group
    if (!m_itemIdsInSet.isEmpty()) {
        auto setIds = m_itemIdsInSet.keys();
        for (auto &id : qAsConst(setIds)) {
            if (id != kTaskbarGroupId) {
                placeGroup(id);
            }
        }
    }
    // place the app icon
    placeAppIcons();
}

void TabletDesktopItemLoader::loadTaskbarApps()
{
    auto desktopFiles = m_taskbarAppManager->appDesktopfiles();
    QList<int> appIds;
    QList<QList<int>> taskbarAppIds;
    for (auto &desktopFile : qAsConst(desktopFiles)) {
        auto tmp = desktopFile.split("/");
        QString desktopName = tmp.isEmpty() ? desktopFile : tmp.constLast();
        int appId = DesktopItemHelper::appIdByDesktopFromAllItems(desktopName, m_allItems);
        appIds.append(appId);
    }
    taskbarAppIds.append(appIds);
    m_itemIdsInSet[kTaskbarGroupId] = taskbarAppIds;

    UKUI::GroupItem *groupItem = new UKUI::GroupItem("taskbar", kTaskbarGroupId);
    m_allItems[kTaskbarGroupId] = groupItem;
}

void TabletDesktopItemLoader::loadDefaultGroup()
{
    auto defaultGroup = m_config.defaultGroups();
    auto it = defaultGroup.constBegin();
    while (it != defaultGroup.constEnd()) {
        loadGroupFromConfig(it.key(), it.value());
        ++ it;
    }

    qDebug() << "sets id: " << m_itemIdsInSet;
}

void TabletDesktopItemLoader::loadAppWidget()
{
    auto widgetList = m_config.appWidgetList();
    if (widgetList.isEmpty()) {
        return;
    }
    for (auto &widget : qAsConst(widgetList)) {
        QString widgetQmlFilePath = m_appWidgetManager->getAppWidgetUiFile(widget);
        if (widgetQmlFilePath.isEmpty()) {
            qWarning() << "Widget qml file path is empty.";
            continue;
        }
        QString widgetName = m_appWidgetManager->getAppWidgetConfig(widget, AppWidget::NAME);
        QString widgetIconName = m_appWidgetManager->getAppWidgetConfig(widget, AppWidget::PREVIEW_PATH);
        int column = m_appWidgetManager->getAppWidgetConfig(widget, AppWidget::TARGET_CELL_WIDTH).toInt();
        int row = m_appWidgetManager->getAppWidgetConfig(widget, AppWidget::TARGET_CELL_HEIGHT).toInt();
        int widgetId = m_allItems.count() + 1;
        UKUI::Widget *w = new UKUI::Widget(widgetQmlFilePath, widgetName, widgetId, QList<int>() << row << column);
        qDebug() << __func__ << row << column;
        m_allItems[widgetId] = w;
        m_appWidgetIds.append(widgetId);
    }
    qDebug() << "m_appWidgetIds" << m_appWidgetIds;
}

void TabletDesktopItemLoader::loadGroupFromConfig(const QString &groupName, const QStringList &desktopFiles)
{
    int groupId = m_allItems.count() + 1;
    QList<int> idList;
    for (auto &desktopName : qAsConst(desktopFiles)) {
        int appId = DesktopItemHelper::appIdByDesktopFromAllItems(desktopName, m_allItems);
        qDebug() << appId << DesktopItemHelper::itemExistsInSet(appId, m_itemIdsInSet);
        if (appId == -1 || DesktopItemHelper::itemExistsInSet(appId, m_itemIdsInSet)) {
            continue;
        }
        idList.append(appId);
        if (idList.size() >= 16) {
            m_itemIdsInSet[groupId].append(idList);
            idList.clear();
        }
    }
    if (!idList.isEmpty()) {
        m_itemIdsInSet[groupId].append(idList);
    }
    QString translatedGroupName = UKUI::translatedName(groupName);
    UKUI::GroupItem *groupItem = new UKUI::GroupItem(translatedGroupName, groupId);
    groupItem->setSourceName(DEFAULT_GROUP_NAME_PREFIX + groupName);
    m_allItems[groupId] = groupItem;
}

void TabletDesktopItemLoader::placeAppWidget(UKUI::ItemId appWidgetId)
{
    AppWidgetPositionCalculator calculator;
    int row = m_allItems[appWidgetId]->getPlaceHolder().constFirst();
    int column = m_allItems[appWidgetId]->getPlaceHolder().constLast();
    int appWidgetPage, appWidgetPageRow, appWidgetPageColumn;
    std::tie(appWidgetPage, appWidgetPageRow, appWidgetPageColumn) =
            calculator.calculationPosition(m_desktopLayout.row,
                                           m_desktopLayout.column,
                                           m_itemIdsInPageGrid, row, column);
    if (appWidgetPage == -1) {
        return;
    }
    placeItem({ appWidgetId, appWidgetPage, appWidgetPageRow, appWidgetPageColumn, row, column });
    qDebug() << __FUNCTION__ << m_itemIdsInPageGrid;
}

void TabletDesktopItemLoader::placeGroup(UKUI::ItemId groupId)
{
    AppItemPositionCalculator calculator;
    int page, row, column;
    std::tie(page, row, column) = calculator.calculationPosition(
                m_desktopLayout.row, m_desktopLayout.column,
                m_itemIdsInPageGrid, 1, 1);
    placeItem({ groupId, page, row, column, 1, 1 });
    qDebug() << __FUNCTION__ << m_itemIdsInPageGrid;
}

void TabletDesktopItemLoader::placeAppIcons()
{
    AppItemPositionCalculator calculator;
    auto allItemIds = m_allItems.keys();
    for (auto &id : qAsConst(allItemIds)) {
        if (m_appWidgetIds.contains(id) ||
                m_itemIdsInSet.contains(id) ||
                DesktopItemHelper::itemExistsInSet(id, m_itemIdsInSet)) {
            continue;
        }
        int page, row, column;
        std::tie(page, row, column) = calculator.calculationPosition(
                    m_desktopLayout.row, m_desktopLayout.column,
                    m_itemIdsInPageGrid, 1, 1);
        placeItem({ id, page, row, column, 1, 1 });
    }
    qDebug() << __FUNCTION__ << m_itemIdsInPageGrid;
}

EduScreenDesktopItemLoader::EduScreenDesktopItemLoader(DesktopFileManager *desktopFileManager,
                                                       DesktopLayout desktopLayout,
                                                       QObject *parent)
    : DesktopItemLoader(desktopFileManager, desktopLayout, parent)
{

}

void EduScreenDesktopItemLoader::loadLocalItems()
{
    loadDefaultContainer();
}

void EduScreenDesktopItemLoader::placeItems()
{    
    if (!m_itemIdsInSet.isEmpty()) {
        auto setIds = m_itemIdsInSet.keys();
        for (auto &id : qAsConst(setIds)) {
            placeContainer(id);
        }
    }
}

void EduScreenDesktopItemLoader::loadDefaultContainer()
{
    auto defaultContainer = m_config.defaultContainers();
    for (auto container : defaultContainer) {
        loadContainerFromConfig(container);
        qDebug() << __func__ << container.containerName << container.placeholder << container.titleEditable;
    }
    qDebug() << "container id: " << m_itemIdsInSet;
}

void EduScreenDesktopItemLoader::loadContainerFromConfig(const Config::ContainerInfo containerInfo)
{
    int containerId = m_allItems.count() + 1;
    if (containerInfo.placeholder.count() < 2) {
        qWarning() << __func__ << "placeholder count less than 2 !!!";
        return;
    }
    int containerCount = containerInfo.placeholder.value(0) * containerInfo.placeholder.value(1);
    if (containerCount <= 0) {
        qWarning() << __func__ << "containerCount is valid !!!";
        return;
    }
    QList<int> idList;
    for (auto &desktopName : qAsConst(containerInfo.desktopFiles)) {
        int appId = DesktopItemHelper::appIdByDesktopFromAllItems(desktopName, m_allItems);
        qDebug() << __func__ << appId << DesktopItemHelper::itemExistsInSet(appId, m_itemIdsInSet);
        if (appId == -1 || DesktopItemHelper::itemExistsInSet(appId, m_itemIdsInSet)) {
            continue;
        }
        idList.append(appId);
        if (idList.size() >= containerCount) {
            m_itemIdsInSet[containerId].append(idList);
            idList.clear();
        }
    }
    if (!idList.isEmpty() || m_itemIdsInSet.value(containerId).count() == 0) {
        m_itemIdsInSet[containerId].append(idList);
    }
    UKUI::ContainerItem *containerItem = new UKUI::ContainerItem(containerInfo.containerName,
                                                                 containerId,
                                                                 containerInfo.placeholder,
                                                                 containerInfo.titleEditable,
                                                                 containerInfo.containerEditable,
                                                                 containerInfo.containerCategory);
    m_allItems[containerId] = containerItem;
}

void EduScreenDesktopItemLoader::placeContainer(UKUI::ItemId containerId)
{
    AppWidgetPositionCalculator calculator;
    int row = m_allItems[containerId]->getPlaceHolder().constFirst();
    int column = m_allItems[containerId]->getPlaceHolder().constLast();

    int cotainerPage, containerRow, containerColumn;
    std::tie(cotainerPage, containerRow, containerColumn) =
            calculator.calculationPosition(m_desktopLayout.row,
                                           m_desktopLayout.column,
                                           m_itemIdsInPageGrid, row, column);
    if (cotainerPage == -1) {
        return;
    }
    placeItem({ containerId, cotainerPage, containerRow, containerColumn, row, column });
    qDebug() << __FUNCTION__ << m_itemIdsInPageGrid;
}

